﻿using FDSimpleModelGenerator.Common;
using FDSimpleModelGenerator.Common.Enums;
using FDSimpleModelGenerator.Entities;
using FDSimpleModelGenerator.Entities.Exceptions;
using FDSimpleModelGenerator.IServices;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace FDSimpleModelGenerator.Services
{
    /// <summary>
    /// 模型生成器
    /// </summary>
    public class ModelGenerateEngine : IModelGenerateEngine
    {
        private readonly IExceptionThrowFactory _exceptionThrowFactory;
        private readonly IEnumerable<IDataTypeMapperService> _dataTypeMapperServices;

        public ModelGenerateEngine(IExceptionThrowFactory exceptionThrowFactory, IEnumerable<IDataTypeMapperService> dataTypeMapperServices)
        {
            _dataTypeMapperServices = dataTypeMapperServices;
            _exceptionThrowFactory = exceptionThrowFactory;
        }

        public IDataTypeMapperService GeTypeMapperService(LanguageDataType languageDataType)
        {
            return _dataTypeMapperServices.First(d => d.LanguageDataType == languageDataType);
        }

        /// <summary>
        /// 生成模型
        /// </summary>
        /// <param name="tableInfo"></param>
        /// <param name="templateContent"></param>
        /// <param name="namespaceName"></param>
        /// <param name="propertyFirstCharLower"></param>
        /// <param name="languageDataType"></param>
        /// <returns></returns>
        public string Generate(TableInfo tableInfo, string templateContent, string namespaceName, LanguageDataType languageDataType, bool propertyFirstCharLower)
        {
            var sb = new StringBuilder();
            var className = TableFormatter.FormatClassName(tableInfo.Name);
            var classDesc = TableFormatter.FormatClassDescription(tableInfo.Description.IsNullOrEmpty() ? className : tableInfo.Description);

            var item = GetItem(templateContent, out string originItem);
            foreach (var column in tableInfo.TableColumns)
            {
                var cName = TableFormatter.FormatClassName(column.Name, propertyFirstCharLower ? CharacterFormat.FirstLower : CharacterFormat.FirstUpper);
                var desc = column.Description + $"{(column.Key ? "【主键】" : "")}";
                desc = desc.IsNullOrEmpty() ? cName : desc;
                var temp = item.Replace(TemplateConstrants.ClassName, className)
                    .Replace(TemplateConstrants.ItemDescription, desc)
                    .Replace(TemplateConstrants.ItemType, GeTypeMapperService(languageDataType).Map(column.ColumnType, column.Unsigned))
                    .Replace(TemplateConstrants.ItemName, cName);
                sb.Append(temp);
            }

            var content = templateContent.Replace(originItem, sb.ToString());

            namespaceName = namespaceName.IsNullOrEmpty() ? "NoNameSpace" : namespaceName;

            return content.Replace(TemplateConstrants.ClassName, className)
                .Replace(TemplateConstrants.NameSpace, namespaceName)
                .Replace(TemplateConstrants.ClassDescription, classDesc);
        }

        public async Task<string> GenerateAsync(TableInfo tableInfo, string templateContent, string namespaceName,
            LanguageDataType languageDataType, bool propertyFirstCharLower = false)
        {
            return await Task.Run(() => Generate(tableInfo, templateContent, namespaceName, languageDataType, propertyFirstCharLower));
        }

        private string GetItem(string content, out string originItem)
        {
            var beg = content.IndexOf(TemplateConstrants.ItemBegin);
            var end = content.IndexOf(TemplateConstrants.ItemEnd);
            if (beg == -1 || end == -1)
            {
                _exceptionThrowFactory.Throw<GenerateException>("模板内容错误");
            }

            var len = end + TemplateConstrants.ItemEnd.Length - beg;
            originItem = content.Substring(beg, len);
            var item = originItem
                .Replace(TemplateConstrants.ItemBegin, "")
                .Replace(TemplateConstrants.ItemEnd, "");
            return item;
        }
    }
}
